#include "TADComunicacion.h"
#include "Estructuras.h"
#include "Ppd_funciones.h"



/*
  El Proceso Emisor enviara un paquete NIPC extendido con los siguiintes valores específicos:
  Type: 0 ( El 0 indica que el paquete es del tipo Handshake )
  Payload: El idintificador del disco o nada si no es un disco.
*/

int32_t HandShakeEmisor(int32_t Sock,int32_t SoyDisco){
	TMensaje *Mensaje;
	TMensaje *OtroMensaje;
	int32_t bytesRec=0,largo;
	time_t tActual;
	struct tm* tiempoGenerico;
	char cad[50];
	char MensajeP[1100];
	char *miNombre;
	tActual = time(NULL);
	tiempoGenerico = localtime(&tActual);
	strftime(cad, 50, "%H%M%S", tiempoGenerico);
	Mensaje=(TMensaje*)calloc(1,sizeof(TMensaje));
	memset(Mensaje->payload,'\0',1100);
	sprintf(Mensaje->idDescriptor,"%s%010i",cad,rand()); // OBTENGO ASUNTO RANDOM
	//miNombre=(char*)malloc(30);
	extern int32_t cantidadSectoresPorPista;
	extern int32_t cantPistas;
	extern int32_t flagSincronizacion;


	if(SoyDisco){
		miNombre=obtenerNombreDisco();
		sprintf(miNombre,"%s(%d,%d,%d)",miNombre,cantPistas,1,cantidadSectoresPorPista);
		strcpy(Mensaje->payload,miNombre); // ESTE NOMBRE EN REALIDAD SE SACA DEL ARCHIVO DE CONFIGURACION
		Mensaje->payloadLength=strlen(Mensaje->payload);
	}
	else{
		Mensaje->payloadLength=0;
	}
	free(miNombre);
	Mensaje->payloadDescriptor='0'; // TYPE CERO POR HANDSHAKE
	send(Sock,(void*)Mensaje,sizeof(struct TMensaje),0);  // ENVIO REQUEST DE HANDSHAKE
	free(Mensaje);
	OtroMensaje=(TMensaje*)calloc(1,sizeof(TMensaje));

	while(bytesRec<=0){
		bytesRec=recv(Sock,(void*)OtroMensaje,sizeof(struct TMensaje),0); // RECIBO RESPUESTA DE HANDSHAKE
	}
	largo=OtroMensaje->payloadLength;
	strcpy(MensajeP,OtroMensaje->payload);
	free(OtroMensaje);
	if(!strcmp(MensajeP,"Sincronizate"))
		flagSincronizacion=1;
	if(largo==0){
		printf("\nHandShake realizado correctamente\n");
		return 1;
	}
	else{
		printf("\nNo se pudo realizar el HandShake\nCodigo de Error:%s",MensajeP); //Voy a devolver cero en la funcion despues afuera cierro el socket,etc.
		return 0;
	}

}


/*El Proceso Receptor segun quien sea ( Si soy un Raid o no) debe  responder con un paquete NIPC
  con los siguiintes valores específicos:
  Type: 0 ( El 0 indica que el paquete es del tipo Handshake )
  Payload:
  Vacío, por lo que Payload Length sera 0, en caso de que la conexión se correcta
  Código/Mensaje de error indicando que la negociación fue fallida y el motivo de
  esto. Luego de enviar este paquete el Proceso RAID cierra la conexión.

*/


int32_t HandShakeReceptor(int32_t sock,int32_t cantDisp,int32_t SoyRaid,int32_t EstaP){  //Si es un Raid me interesa saber si tengo un planificador intonces tengo variable EstaP

	int32_t Largo;
	int32_t bytesRec=0;
	TMensaje *TheirM,*MyM;
	TheirM=(TMensaje*)calloc(1,sizeof(TMensaje));
	while(bytesRec<=0){
	  bytesRec=recv(sock, (void*)TheirM, sizeof(struct TMensaje), 0);  // RECIBO REQUEST
	}
	bytesRec= 0;
	MyM=(TMensaje*)calloc(1,sizeof(TMensaje));
	memset(MyM->payload,'\0',1100);
	strcpy(MyM->idDescriptor ,TheirM->idDescriptor);
	Largo= TheirM->payloadLength;
	free(TheirM);
	MyM->payloadDescriptor='0';
	if(SoyRaid){ // SOY UN RAID
		if(cantDisp < 10){
			if(Largo != 0){ //ES UN PLANIFICADOR QUIEN ME HABLA
				//TODO OKEY
				MyM->payloadLength= 0;
				send(sock,(void*)MyM,sizeof(struct TMensaje),0); //ENVIO RESPONSE
				free(MyM);
				return 1;
			}
			else{ //NO ES UN PLANIFICADOR QUIEN ME HABLA
				if(EstaP){//TENEMOS UN PLANIFICADOR
					//TODO OKEY
					MyM->payloadLength= 0;
					send(sock,(void*)MyM,sizeof(struct TMensaje),0); //ENVIO RESPONSE
					free(MyM);
					return 1;
				}
				else{// NO TENEMOS UN PLANIFICADOR
					strcpy(MyM->payload,"El RAID NO SE ENCUintRA EN ESTADO ACTIVO\n");
					MyM->payloadLength=strlen("El RAID NO SE ENCUintRA EN ESTADO ACTIVO\n");
					send(sock,(void*)MyM,sizeof(struct TMensaje),0); //ENVIO RESPONSE
					close(sock);
					free(MyM);
					return 0;
				}
			}
		}
		else{//TENEMOS MUCHOS DISPOSITIVOS
			//HandShakeReceptor
			strcpy(MyM->payload,"El RAID NO ADMITE MAS CONEXIONES\n");
			MyM->payloadLength=strlen("El RAID NO ADMITE MAS CONEXIONES\n");
			send(sock,(void*)MyM,sizeof(struct TMensaje),0); //ENVIO RESPONSE
			close(sock);
			free(MyM);
			return 0;
		}
	}
	else{ // NO SOY UN RAID
			//POR LO PRONTO VAMOS A ACEPTAR SIEMPRE PUESTO QUE NO VEO CASO intRE PPD Y PFS QUE FALLE
			MyM->payloadLength= 0;
			send(sock,(void*)MyM,sizeof(struct TMensaje),0); //ENVIO RESPONSE
			free(MyM);
			return 1;
	}


}

//FUNCION QUE ENVIA UN MENSAJE NIPC EXTENDIDO SIN ESPERAR RESPUESTA ( ASINCRONICAMintE )
int32_t ComunicacionA(int32_t sock,char desc,char *cadena,char *id){

	TMensaje *Mensaje;
	extern int32_t SockConsola;
	int32_t bytes=-1;
	int32_t cont=0;


	Mensaje=(TMensaje*)calloc(1,sizeof(TMensaje));

	memcpy(Mensaje->idDescriptor,id,16);
	Mensaje->payloadDescriptor = desc;
	Mensaje->payloadLength=512;

	memcpy(Mensaje->payload,cadena,512);
	/*if(sock==SockConsola)
		printf("Envie a la Consola: %s\n",Mensaje->payload);
	else
		printf("Envie: %s\n",Mensaje->payload);
	*/
	
	while(bytes==-1){
		bytes=send(sock,(void*)Mensaje,sizeof(struct TMensaje),0);
	//	if(bytes==-1)
			//perror("fallo send");
	}
	free(Mensaje);
	return 0;
}


/*
Funcion especifica del Raid para obtener el tipo y nombre de los dispositivos que se estan conectando

*/
TInfo *ObtenerNombre(int32_t sock){

	TMensaje *Mensaje,*OtroMensaje;
	int32_t bytesRec=0;
	time_t tActual;
	TInfo *Info=(TInfo*)calloc(1,sizeof(TInfo));
	struct tm* tiempoGenerico;
	char cad[50];
	tActual = time(NULL);
	tiempoGenerico = localtime(&tActual);
	strftime(cad, 50, "%H%M%S", tiempoGenerico);
	Mensaje=(TMensaje*)calloc(1,sizeof(TMensaje));
	sprintf(Mensaje->idDescriptor,"%s%010i",cad,rand());
	Mensaje->payloadDescriptor='R';
	Mensaje->payloadLength=(int32_t)strlen("hola");
	strcpy(Mensaje->payload,"hola");
	send(sock,(void*)Mensaje,sizeof(struct TMensaje),0); //ENVIO SALUDO "HOLA"
	free(Mensaje);
	OtroMensaje=(TMensaje*)calloc(1,sizeof(TMensaje));
	while(bytesRec<=0){
	  bytesRec=recv(sock, (void*)OtroMensaje, sizeof(struct TMensaje), 0);  // RECIBO REQUEST
	}
	strcpy(Info->Nombre,OtroMensaje->payload);
	Info->Tipo=OtroMensaje->payloadDescriptor;
	free(OtroMensaje);
	return Info;
}


/*

Funcion que intrega el nombre al pedido "ObtenerNombre()" del RAID usada por PPD y PFS

*/
int32_t Nombre(int32_t Sock,char *nombre,char Tipo){ // "Tipo" es 'F' si PFS o 'P' si Planificador
	int32_t bytesRec= 0,valor;
	TMensaje *TheirM;
	TMensaje *MyM;

	TheirM=(TMensaje*)calloc(1,sizeof(TMensaje));

	while(bytesRec<=0){
		bytesRec=recv(Sock, (void*)TheirM, sizeof(struct TMensaje), 0);
	}

	if(!strcmp(TheirM->payload,"hola")){

		MyM=(TMensaje*)calloc(1,sizeof(TMensaje));
		strcpy(MyM->idDescriptor ,TheirM->idDescriptor);
		strcpy(MyM->payload,nombre);
		MyM->payloadLength=30;
		MyM->payloadDescriptor=Tipo;
		valor=send(Sock,(void*)MyM,sizeof(struct TMensaje),0);
		free(MyM);
	    free(TheirM);
	}
	return 0;
}


/*Funcion que obtiene OpcionLog*/
int32_t obtenerOpcionLog(){
	int32_t bytesRec=0;
	extern int32_t SockConsola;
	int32_t largo;
	TMensaje *OtroMensaje;
	char opc[10];
	int32_t opcion;
	
	OtroMensaje=(TMensaje*)calloc(1,sizeof(TMensaje));

	while(bytesRec<=0){
		bytesRec=recv(SockConsola,(void*)OtroMensaje,sizeof(struct TMensaje),0); // RECIBO RESPUESTA DE HANDSHAKE
	}
	largo=OtroMensaje->payloadLength;
	strcpy(opc,OtroMensaje->payload);
	free(OtroMensaje);
	opc[1]='\0';
	opcion=atoi(opc);
	
	return opcion;
}




